home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume4 / dos-fft < prev    next >
Encoding:
Text File  |  1989-02-03  |  11.7 KB  |  505 lines

  1. Path: xanth!mcnc!gatech!bloom-beacon!husc6!m2c!necntc!ncoast!allbery
  2. From: sampson@killer.DALLAS.TX.US (Steve Sampson)
  3. Newsgroups: comp.sources.misc
  4. Subject: v04i009: An FFT program
  5. Message-ID: <5045@killer.DALLAS.TX.US>
  6. Date: 1 Aug 88 01:44:07 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Reply-To: sampson@killer.DALLAS.TX.US (Steve Sampson)
  9. Organization: The Unix(R) Connection, Dallas, Texas
  10. Lines: 492
  11. Approved: allbery@ncoast.UUCP
  12.  
  13. Posting-number: Volume 4, Issue 9
  14. Submitted-by: "Steve Sampson" <sampson@killer.DALLAS.TX.US>
  15. Archive-name: dos-fft
  16.  
  17. [MS-DOS C of some kind -- you may have to patch "fopen"'s under Unix.  At
  18. least.  No binaries were provided.  ++bsa]
  19.  
  20. #! /bin/sh
  21. # This is a shell archive.  Remove anything before this line, then unpack
  22. # it by saving it into a file and typing "sh file".  To overwrite existing
  23. # files, type "sh file -c".  You can also feed this as standard input via
  24. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  25. # will see the following message at the end:
  26. #        "End of shell archive."
  27. # Contents:  readme.doc gen.c fft.c
  28. # Wrapped by sampson@killer on Sun Jul 31 20:40:12 1988
  29. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  30. if test -f readme.doc -a "${1}" != "-c" ; then 
  31.   echo shar: Will not over-write existing file \"readme.doc\"
  32. else
  33. echo shar: Extracting \"readme.doc\" \(3814 characters\)
  34. sed "s/^X//" >readme.doc <<'END_OF_readme.doc'
  35. XI originally saw an FFT program in Byte Magazine many years ago.  I wrote
  36. Xa version for BASIC that worked pretty good.  Then I thought I'd translate
  37. Xit into C.  These programs are the result.  I don't do windows though...
  38. X
  39. XNeeds a graphic interface, but the time escapes me.  Please upload any better
  40. Xgraphic versions.
  41. X
  42. XThe original Byte Magazine program was designed for real data only.  In my
  43. Xexperiments I needed to preserve both real and imaginary data.  If you feed
  44. Xthe FFT real data only, then the output will be a mirror image, and you can
  45. Xignore the left side.
  46. X
  47. XFor an example try:
  48. X
  49. X    gen 16 in
  50. X    1000
  51. X    3000
  52. X
  53. XWhich will sample the 1 Khz data every 333 microseconds (1 / 3 Khz).
  54. XNote: The sample frequency should be greater than 2 times the input
  55. Xfrequency (Nyquist and all that...).
  56. X
  57. XThen run fft.exe like so:
  58. X
  59. X    fft 16 in out
  60. X
  61. XAnd you should see a display like so:
  62. X
  63. X0    |=======                      (-1500.0 Hz)
  64. X1    |=====                          (-1312.5 Hz)
  65. X2    |====                          (-1125.0 Hz)
  66. X3    |====                           (-937.0 Hz)
  67. X4    |===                           (-750.0 Hz)
  68. X5    |===                           (-562.5 Hz)
  69. X6    |===                           (-375.0 Hz)
  70. X7    |===                           (-187.5 Hz)
  71. X8    |====        <-------   DC            (000.0 Hz)
  72. X9    |====        <-------   Fundamental        (187.5 Hz)
  73. X10    |======        <-------   Second Harmonic    (375.0 Hz)
  74. X11    |========                    (562.5 Hz)
  75. X12    |==============                    (750.0 Hz)
  76. X13    |========================================================
  77. X14    |============================            (1125.0 Hz)    ^
  78. X15    |===========                    (1312.5 Hz)    |
  79. X                                |
  80. X                [13 - 8 (center)] * 187.5 = 937.0 Hz
  81. X
  82. XThe fundamental display frequency is:
  83. X
  84. X    T  = Time Increment Between Samples
  85. X    N  = Number Of Samples
  86. X    Tp = N * T
  87. X
  88. X    Then F = 1 / Tp
  89. X
  90. X    In the example above, the time increment between samples is
  91. X    1 / 3000 or 333 microseconds.  N = 16, so Tp = 5333 microseconds
  92. X    and 1 / .005333 is 187.5 Hz.
  93. X
  94. X    Therefore each filter is a multiple of 187.5 Hertz.  Filter 8 in this
  95. X    example is center, so that would be zero, 9 would be one, etc.
  96. X
  97. XIn this case the sample interval didn't work so good for the frequency and
  98. Xshows the limitation of the Discrete Fourier Transform in representing a
  99. Xcontinuous signal.  A better sample rate for 1000 Hz would be 4000 Hz,
  100. Xin which case T = 250 ms, Tp = 4 ms, and F = 250 Hz.  1000 / 250 = 4.  The
  101. Xpower should all be in filter 12 (8 + 4) in this case.
  102. X
  103. XLet's run it and see:
  104. X
  105. X    gen 16 in
  106. X    1000
  107. X    4000
  108. X
  109. X    fft 16 in out
  110. X
  111. X0    |
  112. X1    |
  113. X2    |
  114. X3    |
  115. X4    |
  116. X5    |
  117. X6    |
  118. X7    |
  119. X8    |
  120. X9    |
  121. X10    |
  122. X11    |
  123. X12    |========================================================
  124. X13    |
  125. X14    |
  126. X15    |
  127. X
  128. XWell what do you know...
  129. X
  130. XThe output file data can be used by other programs as needed.
  131. X
  132. XBy using negative frequencies in gen.exe you can generate opening targets:
  133. X
  134. X    gen 16 in
  135. X    -1000
  136. X    3000
  137. X    fft 16 in out
  138. X
  139. XProduces:
  140. X
  141. X0    |=======
  142. X1    |===========
  143. X2    |============================
  144. X3    |=======================================================
  145. X4    |==============
  146. X5    |========
  147. X6    |======
  148. X7    |====
  149. X8    |====        <-------- Zero Hertz (DC)
  150. X9    |===
  151. X10    |===
  152. X11    |===
  153. X12    |===
  154. X13    |====
  155. X14    |====
  156. X15    |=====
  157. X
  158. XYou can see in these examples where weighting functions would be nice.
  159. XFor an example of what happens when the imaginary data is not input
  160. X(ie, zeros put in) for a 1000 Hz frequency at 3000 Hz sample rate:
  161. X
  162. X0    |===============
  163. X1    |==================
  164. X2    |===================================
  165. X3    |========================================================
  166. X4    |===========
  167. X5    |====
  168. X6    |==
  169. X7    |=                Trash this part
  170. X---------------------------------------------------------------------
  171. X8    |
  172. X9    |=
  173. X10    |==
  174. X11    |====
  175. X12    |===========
  176. X13    |=======================================================
  177. X14    |===================================
  178. X15    |==================
  179. X
  180. XThe left side is redundant and can be deleted.  This is what the original
  181. XByte Magazine article did (December 1978 Issue).
  182. X
  183. XGood luck, have fun with it,
  184. XSteve Sampson, CompuServe: 75136,626  Unix: sampson@killer.dallas.tx.us
  185. END_OF_readme.doc
  186. if test 3814 -ne `wc -c <readme.doc`; then
  187.     echo shar: \"readme.doc\" unpacked with wrong size!
  188. fi
  189. # end of overwriting check
  190. fi
  191. if test -f gen.c -a "${1}" != "-c" ; then 
  192.   echo shar: Will not over-write existing file \"gen.c\"
  193. else
  194. echo shar: Extracting \"gen.c\" \(1292 characters\)
  195. sed "s/^X//" >gen.c <<'END_OF_gen.c'
  196. X/*
  197. X *    gen.c
  198. X *
  199. X *    C Version 1.0 by Steve Sampson, Public Domain
  200. X *
  201. X *    This program is used to generate time domain sinewave data
  202. X *    for fft.c.  If you want an opening target - negate the test frequency
  203. X *
  204. X *    Usage: gen samples output
  205. X */
  206. X
  207. X#include <stdio.h>
  208. X#include <alloc.h>
  209. X#include <math.h>
  210. X
  211. X#define    PI2    ((double)2.0 * M_PI)
  212. X
  213. Xmain(argc, argv)
  214. Xint    argc;
  215. Xchar    *argv[];
  216. X{
  217. X    FILE    *fp;
  218. X    double    sample, freq, time, *real, *imag;
  219. X    int    loop, samples;
  220. X
  221. X    if (argc != 3)  {
  222. X        printf("Usage: gen samples output_file\n");
  223. X        printf("Where samples is a power of 2\n");
  224. X        exit(-1);
  225. X    }
  226. X
  227. X    if ((fp = fopen(argv[2], "wb")) == (FILE *)NULL)  {
  228. X        printf("Unable to create write file\n");
  229. X        exit(-1);
  230. X    }
  231. X
  232. X    samples = abs(atoi(argv[1]));
  233. X
  234. X    real = (double *)malloc(samples * sizeof(double));
  235. X    imag = (double *)malloc(samples * sizeof(double));
  236. X
  237. X    printf("Input The Test Frequency (Hz) ? ");
  238. X    scanf("%lf", &freq);
  239. X    printf("Input The Sampling Frequency (Hz) ? ");
  240. X    scanf("%lf", &sample);
  241. X    sample = (double)1.0 / sample;
  242. X
  243. X    time = (double)0.0;
  244. X    for (loop = 0; loop < samples; loop++)  {
  245. X        real[loop] =  sin(PI2 * freq * time);
  246. X        imag[loop] = -cos(PI2 * freq * time);
  247. X        time += sample;
  248. X    }
  249. X
  250. X    fwrite(real, sizeof(double), samples, fp);
  251. X    fwrite(imag, sizeof(double), samples, fp);
  252. X
  253. X    fclose(fp);
  254. X    putchar('\n');
  255. X}
  256. X
  257. X/* EOF */
  258. END_OF_gen.c
  259. if test 1292 -ne `wc -c <gen.c`; then
  260.     echo shar: \"gen.c\" unpacked with wrong size!
  261. fi
  262. # end of overwriting check
  263. fi
  264. if test -f fft.c -a "${1}" != "-c" ; then 
  265.   echo shar: Will not over-write existing file \"fft.c\"
  266. else
  267. echo shar: Extracting \"fft.c\" \(4203 characters\)
  268. sed "s/^X//" >fft.c <<'END_OF_fft.c'
  269. X/*
  270. X *    fft.c
  271. X *
  272. X *    C Version 1.0 by Steve Sampson, Public Domain
  273. X *
  274. X *    This program is based on the work by W. D. Stanley
  275. X *    and S. J. Peterson, Old Dominion University.
  276. X *
  277. X *    This program produces a Frequency Domain display
  278. X *    from the Time Domain data input using the Fast Fourier Transform.
  279. X *
  280. X *    The REAL data is generated by the in-phase (I) channel and the
  281. X *    IMAGINARY data is produced by the quadrature-phase (Q) channel of
  282. X *    a Doppler Radar receiver.  The middle filter is zero Hz.  Closing
  283. X *    targets are displayed to the right, and Opening targets to the left.
  284. X *
  285. X *    Note: With IMAGINARY data set to zero the output is a mirror image.
  286. X *
  287. X *    Usage:    fft  samples  input_data  output_data
  288. X *    Where 'samples' is a power of two
  289. X *
  290. X *    Array Version for Turbo C 1.5
  291. X */
  292. X
  293. X/* Includes */
  294. X
  295. X#include <stdlib.h>
  296. X#include <stdio.h>
  297. X#include <math.h>
  298. X#include <alloc.h>
  299. X
  300. X/* Defines */
  301. X
  302. X#define    TWO_PI    ((double)2.0 * M_PI)
  303. X
  304. X/* Globals */
  305. X
  306. Xint    samples, power;
  307. Xdouble    *real, *imag, max;
  308. XFILE    *fpi, *fpo;
  309. X
  310. X/* Prototypes and forward declarations */
  311. X
  312. Xvoid    fft(void), max_amp(void), display(void);
  313. Xint    permute(int);
  314. Xdouble    magnitude(int);
  315. X
  316. X/* The program */
  317. X
  318. Xmain(argc, argv)
  319. Xint    argc;
  320. Xchar    *argv[];
  321. X{
  322. X    int    n;
  323. X
  324. X    if (argc != 4)  {
  325. Xerr1:        fprintf(stderr, "Usage: fft samples input output\n");
  326. X        fprintf(stderr, "Where samples is a power of 2\n");
  327. X        exit(1);
  328. X    }
  329. X
  330. X    samples = abs(atoi(argv[1]));
  331. X    power =  log10((double)samples) / log10((double)2.0);
  332. X
  333. X    if ((real = (double *)malloc(samples * sizeof(double))) == NULL)
  334. Xerr2:        fprintf(stderr, "Out of memory\n");
  335. X
  336. X    if ((imag = (double *)malloc(samples * sizeof(double))) == NULL)
  337. X        goto err2;
  338. X
  339. X    if ((fpo = fopen(argv[3], "wb")) == (FILE *)NULL)
  340. X        goto err1;
  341. X
  342. X    if ((fpi = fopen(argv[2], "rb")) != (FILE *)NULL)  {
  343. X        fread(real, sizeof(double), samples, fpi);
  344. X        fread(imag, sizeof(double), samples, fpi);
  345. X        fclose(fpi);
  346. X    }
  347. X    else
  348. X        goto err1;
  349. X
  350. X    fft();
  351. X    max_amp();
  352. X    display();
  353. X
  354. X    fwrite(real, sizeof(double), samples, fpo);
  355. X    fwrite(imag, sizeof(double), samples, fpo);
  356. X
  357. X    fclose(fpo);
  358. X}
  359. X
  360. X
  361. Xvoid fft()
  362. X{
  363. X    unsigned i1, i2, i3, i4, y;
  364. X    int     loop, loop1, loop2;
  365. X    double     a1, a2, b1, b2, z1, z2, v;
  366. X
  367. X    /* Scale the data */
  368. X
  369. X    for (loop = 0; loop < samples; loop++)  {
  370. X        real[loop] /= (double)samples;
  371. X        imag[loop] /= (double)samples;
  372. X    }
  373. X
  374. X    i1 = samples >> 1;
  375. X    i2 = 1;
  376. X    v = TWO_PI * ((double)1.0 / (double)samples);
  377. X
  378. X    for (loop = 0; loop < power; loop++)  {
  379. X        i3 = 0;
  380. X        i4 = i1;
  381. X
  382. X        for (loop1 = 0; loop1 < i2; loop1++)  {
  383. X            y = permute(i3 / i1);
  384. X            z1 =  cos(v * y);
  385. X            z2 = -sin(v * y);
  386. X
  387. X            for (loop2 = i3; loop2 < i4; loop2++)  {
  388. X                a1 = real[loop2];
  389. X                a2 = imag[loop2];
  390. X
  391. X                b1 = z1*real[loop2+i1] - z2*imag[loop2+i1];
  392. X                b2 = z2*real[loop2+i1] + z1*imag[loop2+i1];
  393. X
  394. X                real[loop2]      = a1 + b1;
  395. X                imag[loop2]      = a2 + b2;
  396. X
  397. X                real[loop2 + i1] = a1 - b1;
  398. X                imag[loop2 + i1] = a2 - b2;
  399. X            }
  400. X
  401. X            i3 += (i1 << 1);
  402. X            i4 += (i1 << 1);
  403. X        }
  404. X
  405. X        i1 >>= 1;
  406. X        i2 <<= 1;
  407. X    }
  408. X}
  409. X
  410. X/*
  411. X *    Find maximum amplitude
  412. X */
  413. X
  414. Xvoid max_amp()
  415. X{
  416. X    double    mag;
  417. X    int    loop;
  418. X
  419. X    max = (double)0.0;
  420. X    for (loop = 0; loop < samples; loop++)  {
  421. X        if ((mag = magnitude(loop)) > max)
  422. X            max = mag;
  423. X    }
  424. X}
  425. X
  426. X/*
  427. X *    Display the frequency domain.
  428. X *    The filters are aranged so that DC is in the middle filter.
  429. X *    Thus -Doppler is on the left, +Doppler on the right.
  430. X */
  431. X
  432. Xvoid display()
  433. X{
  434. X    int    c, n, x, loop;
  435. X
  436. X    n = samples / 2;
  437. X    
  438. X    for (loop = n; loop < samples; loop++)  {
  439. X        x = (int)(magnitude(loop) * (double)56.0 / max);
  440. X        printf("%d\t|", loop - n);
  441. X        c = 0;
  442. X        while (++c <= x)
  443. X            putchar('=');
  444. X
  445. X        putchar('\n');
  446. X    }
  447. X
  448. X    for (loop = 0; loop < n; loop++)  {
  449. X        x = (int)(magnitude(loop) * (double)56.0 / max);
  450. X        printf("%d\t|", loop + n);
  451. X        c = 0;
  452. X        while (++c <= x)
  453. X            putchar('=');
  454. X
  455. X        putchar('\n');
  456. X    }
  457. X}
  458. X
  459. X/*
  460. X *    Calculate Power Magnitude
  461. X */
  462. X
  463. Xdouble magnitude(n)
  464. Xint    n;
  465. X{
  466. X    n = permute(n);
  467. X    return (sqrt(real[n] * real[n] + imag[n] * imag[n]));
  468. X}
  469. X
  470. X/*
  471. X *    Bit reverse the number
  472. X *
  473. X *    Change 11100000b to 00000111b or vice-versa
  474. X */
  475. X
  476. Xint permute(index)
  477. Xint    index;
  478. X{
  479. X    int    n1, result, loop;
  480. X
  481. X    n1 = samples;
  482. X    result = 0;
  483. X
  484. X    for (loop = 0; loop < power; loop++)  {
  485. X        n1 >>= 1;            /* n1 / 2.0 */
  486. X        if (index < n1)
  487. X            continue;
  488. X
  489. X        result += (int) pow((double)2.0, (double)loop);
  490. X        index -= n1;
  491. X    }
  492. X
  493. X    return result;
  494. X}
  495. X
  496. X/* EOF */
  497. END_OF_fft.c
  498. if test 4203 -ne `wc -c <fft.c`; then
  499.     echo shar: \"fft.c\" unpacked with wrong size!
  500. fi
  501. # end of overwriting check
  502. fi
  503. echo shar: End of shell archive.
  504. exit 0
  505.